package com.gary.dataPermission;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.gary.enums.DataPermissionDataTypeEnum;
import com.gary.enums.DataPermissionOperatorEnum;
import com.gary.enums.QueryFilterRuleTreeTypeEnum;
import com.gary.enums.RuleParentEnum;
import com.sun.org.slf4j.internal.Logger;
import com.sun.org.slf4j.internal.LoggerFactory;

import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;

/**
 * 数据权限过滤-权限规则实体类翻译器
 * <p> Madison.lu </p>
 * <p>Version: 1.0.0</p>
 * <p>Create Date： 2019/11/5 16:57 </p>
 * <p>Copyright (c) 2017 ~ 2019 Allchips版权所有</p>
 */
public class QueryFilterRuleTranslator {


    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(QueryFilterRuleTranslator.class);

    /**
     * 空格字符
     */
    private static final String SPACER_STRING = " ";

    /**
     * 单引号字符
     */
    private static final String APOSTROPHE_STRING = "'";

    /**
     * 转译单引号
     */
    private static final String TRANSLATION_APOSTROPHE_STRING = "\\'";

    /**
     * 百分号字符
     */
    private static final String PERCENT_SIGN = "%";

    /**
     * 英文逗号
     */
    private static final String EN_COMMA = ",";

    /**
     * 英文逗号
     */
    private static final String CN_COMMA = "，";

    /**
     * 点字符
     */
    private static final String DOT_STRING = ".";
    /**
     * 左括号字符
     */
    private static final String LEFT_PARENTHESIS_STRING = "(";
    /**
     * 右括号字符
     */
    private static final String RIGHT_PARENTHESIS_STRING = ")";

    /**
     * 时间函数左侧
     */
    private static final String TIME_FUNCTION_LEFT = "STR_TO_DATE( ";
    /**
     * 时间函数右侧
     */
    private static final String TIME_FUNCTION_RIGHT = ", '%Y-%m-%d %H:%i:%S' )";
    /**
     * 时间格式
     */
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    /**
     * 时区编号
     */
    private static final ZoneId zoneId = ZoneId.systemDefault();
    /**
     * 可选参数值
     */
    private Map<String, String> params;

    /**
     * 构造函数
     *
     * @param params 可选参数值，即Map<变量名，变量值>
     */
    public QueryFilterRuleTranslator(Map<String, String> params) {
        this.params = params;
    }

    /**
     * 空参构造函数私有化，创建对象必须传可选参数值，即Map<变量名，变量值>占位
     */
    private QueryFilterRuleTranslator() {
    }

    /**
     * 翻译条件对象成sql，得到((a=1)or(b=1)or(c=2)）
     *
     * @param ruleTreeList 条件对象列表
     * @param tableName    表别名
     * @return String 条件sql结果
     */
    public String translateTreeList(List<QueryFilterRuleTree> ruleTreeList, String tableName) throws Exception {


        StringBuilder stringBuilder = new StringBuilder();
        if (CollectionUtil.isEmpty(ruleTreeList)) {
            return "";
        }
        // ruleTreeList是否有多个有效条件对象实体
        boolean isList = false;
        for (QueryFilterRuleTree ruleTree : ruleTreeList) {
            if (ObjectUtil.isNull(ruleTree)) {
                continue;
            }
            String resultStr;
            if (RuleParentEnum.YES.getStatusCode() == ruleTree.getParent()) {
                resultStr = this.translateBranch(ruleTree, tableName);
            } else {
                resultStr = this.translateLeaf(ruleTree, tableName);
            }
            // 如果前面已有条件,且本轮条件结果不为空，则增加连接符 or
            if (StrUtil.isNotEmpty(stringBuilder.toString()) && StrUtil.isNotEmpty(resultStr)) {
                stringBuilder.append(SPACER_STRING);
                stringBuilder.append("OR");
                stringBuilder.append(SPACER_STRING);
                isList = true;
            }
            stringBuilder.append(resultStr);
        }
        // 如果结果不为空，并且有多个条件，增加前后括号
        if (StrUtil.isNotEmpty(stringBuilder.toString()) && isList) {
            stringBuilder.insert(0, SPACER_STRING);
            stringBuilder.insert(0, LEFT_PARENTHESIS_STRING);
            stringBuilder.append(SPACER_STRING);
            stringBuilder.append(RIGHT_PARENTHESIS_STRING);
        }
        return stringBuilder.toString();

    }


    /**
     * 翻译枝节点，
     * 得到“(tableName.fieldName = 'fieldValue' and (tableName.fieldName = '123' or tableName.fieldName =  '123'))”
     * 或“”
     */
    private String translateBranch(QueryFilterRuleTree ruleTree, String tableName) throws Exception {

        StringBuilder stringBuilder = new StringBuilder();
        List<QueryFilterRuleTree> child = ruleTree.getChild();
        if (CollectionUtil.isEmpty(child)) {
            return "";
        }
        for (QueryFilterRuleTree currentRuleTree : child) {
            String resultStr;
            if (RuleParentEnum.YES.getStatusCode() == currentRuleTree.getParent()) {
                resultStr = translateBranch(currentRuleTree, tableName);
            } else {
                resultStr = translateLeaf(currentRuleTree, tableName);
            }
            // 如果前面已有条件,且本轮条件结果不为空，则增加连接符and或or
            if (StrUtil.isNotEmpty(stringBuilder.toString()) && StrUtil.isNotEmpty(resultStr)) {
                if (StrUtil.isEmpty(ruleTree.getLinkOption())) {
                    logger.error("数据权限规则格式不符合规则");
                    throw new Exception("数据权限规则格式不符合规则");
                }

                stringBuilder.append(SPACER_STRING);
                stringBuilder.append(ruleTree.getLinkOption());
                stringBuilder.append(SPACER_STRING);
            }
            stringBuilder.append(resultStr);
        }

        // 如果结果不为空，增加前后括号
        if (StrUtil.isNotEmpty(stringBuilder.toString())) {
            stringBuilder.insert(0, SPACER_STRING);
            stringBuilder.insert(0, LEFT_PARENTHESIS_STRING);
            stringBuilder.append(SPACER_STRING);
            stringBuilder.append(RIGHT_PARENTHESIS_STRING);
        }
        return stringBuilder.toString();
    }

    /**
     * 翻译叶子节点，得到“tableName.fieldName = 'fieldValue'”
     */
    private String translateLeaf(QueryFilterRuleTree ruleTree, String tableName) throws Exception {

        StringBuilder stringBuilder = new StringBuilder();
        // 拼接 表名.字段名
        stringBuilder.append(tableName);
        stringBuilder.append(DOT_STRING);
        stringBuilder.append(ruleTree.getField());

        // 拼接条件，=  < >
        stringBuilder.append(SPACER_STRING);
        stringBuilder.append(ruleTree.getOption());
        stringBuilder.append(SPACER_STRING);
        // 判断值类型，选择值生成方式
        String tempValue = "";
        if (QueryFilterRuleTreeTypeEnum.VARIABLE.getTypeCode() == ruleTree.getOperationType()) {
            // 若是变量则需要取到变量值
            tempValue = this.params.get(ruleTree.getValue());
            if (StrUtil.isEmpty(tempValue)) {
                tempValue = "";
            }
        } else {
            // 其他直接取值，如果值内容包含“'”,替换成“\'”
            tempValue = ruleTree.getValue();
            if (StrUtil.isEmpty(tempValue)) {
                tempValue = "";
            }
            if (tempValue.indexOf(APOSTROPHE_STRING) > 0) {
                tempValue = tempValue.replace(APOSTROPHE_STRING, TRANSLATION_APOSTROPHE_STRING);
            }
        }
        StringBuilder valueBuilder = new StringBuilder();
        // 判断条件类型
        if (DataPermissionOperatorEnum.IN.getName().equalsIgnoreCase(ruleTree.getOption()) ||
                DataPermissionOperatorEnum.NOT_IN.getName().equalsIgnoreCase(ruleTree.getOption())) {
            // in与not in,替换中文逗号
            if (tempValue.indexOf(CN_COMMA) > 0) {
                tempValue = tempValue.replace(CN_COMMA, EN_COMMA);
            }
            // 截取所有值内容，增加单引号
            String[] values = tempValue.split(EN_COMMA);
            StringBuilder stringBuilder4Values = new StringBuilder();
            for (String value : values) {
                if (StrUtil.isNotEmpty(stringBuilder4Values.toString())) {
                    stringBuilder4Values.append(EN_COMMA);
                }
                stringBuilder4Values.append(APOSTROPHE_STRING);
                stringBuilder4Values.append(value);
                stringBuilder4Values.append(APOSTROPHE_STRING);
            }
            valueBuilder.append(stringBuilder4Values);
            // 补“()”
            valueBuilder.insert(0, LEFT_PARENTHESIS_STRING);
            valueBuilder.append(RIGHT_PARENTHESIS_STRING);
        } else if (DataPermissionOperatorEnum.LIKE.getName().equalsIgnoreCase(ruleTree.getOption())) {
            // like，补“'%%'”
            valueBuilder.append(tempValue);
            valueBuilder.insert(0, PERCENT_SIGN);
            valueBuilder.append(PERCENT_SIGN);
            valueBuilder.insert(0, APOSTROPHE_STRING);
            valueBuilder.append(APOSTROPHE_STRING);
        } else if (DataPermissionOperatorEnum.IS.getName().equalsIgnoreCase(ruleTree.getOption())) {
            // 是“is”,直接拼进去
            valueBuilder.append(tempValue);
        } else {
            // 其他并且不是“is”，补“''”
            valueBuilder.append(tempValue);
            valueBuilder.insert(0, APOSTROPHE_STRING);
            valueBuilder.append(APOSTROPHE_STRING);
        }
        // 判断是否是时间，是则加时间函数
        DataPermissionDataTypeEnum dataPermissionDataTypeEnum = DataPermissionDataTypeEnum.get(ruleTree.getType());
        if (dataPermissionDataTypeEnum != null
                && DataPermissionDataTypeEnum.TIME.getCategory().equalsIgnoreCase(dataPermissionDataTypeEnum.getCategory())
                && (!DataPermissionOperatorEnum.IS.getName().equalsIgnoreCase(ruleTree.getOption()))) {
            valueBuilder.insert(0, TIME_FUNCTION_LEFT);
            valueBuilder.append(TIME_FUNCTION_RIGHT);
        }
        // 添加拼接好的值
        stringBuilder.append(valueBuilder);
        return stringBuilder.toString();
    }
}
